/*
 ------------------------------------------------------------------------------
 Copyright (C) 2006-2007 Team Blur.

 This file is part of the Quantum Engine source code.

 The Quantum Engine source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The Quantum Engine source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the Quantum Engine source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


#ifndef __MATH_VECTOR_H__
#define __MATH_VECTOR_H__


extern odVec2		vec2_origin;
extern odVec3		vec3_origin;
extern odVec4		vec4_origin;
extern odVec5		vec5_origin;

/*
 ==============================================================================

 2D VECTOR

 ==============================================================================
*/

class odVec2 {
public:
	float			x;
	float			y;

					odVec2 (void);
	explicit		odVec2 (float x, float y);

	float			operator [] (int index) const;
	float &			operator [] (int index);

	odVec2 &		operator = (const odVec2 &vec);
	bool			operator == (const odVec2 &vec) const;
	bool			operator != (const odVec2 &vec) const;

	odVec2			operator - () const;

	odVec2			operator + (const odVec2 &vec) const;
	odVec2			operator - (const odVec2 &vec) const;
	odVec2			operator * (const odVec2 &vec) const;
	odVec2			operator * (float scale) const;
	odVec2			operator / (const odVec2 &vec) const;
	odVec2			operator / (float div) const;
	odVec2 &		operator += (const odVec2 &vec);
	odVec2 &		operator -= (const odVec2 &vec);
	odVec2 &		operator *= (const odVec2 &vec);
	odVec2 &		operator *= (float scale);
	odVec2 &		operator /= (const odVec2 &vec);
	odVec2 &		operator /= (float div);

	bool			Compare (const odVec2 &vec) const;
	bool			Compare (const odVec2 &vec, float epsilon = 0.0f) const;
	void			Set (float x, float y);
	void			Clear (void);
	bool			IsCleared (void) const;
	void			Snap (void);
	void			Clamp (const odVec2 &min, const odVec2 &max);
	void			Clamp (float min, float max);
	void			Average (const odVec2 &v1, const odVec2 &v2);
	float			Dot (const odVec2 &vec) const;
	void			Lerp (const odVec2 &from, const odVec2 &to, float frac);
	float			Length (void) const;
	float			LengthSqr (void) const;
	float			LengthFast (void) const;
	float			Normalize (void);
	void			NormalizeFast (void);

	const float *	ToFloatPtr (void) const;
	float *			ToFloatPtr (void);

	const char *	ToString (int precision = 2) const;
};

INLINE odVec2::odVec2 (void){

}

INLINE odVec2::odVec2 (float x, float y){

	this->x = x;
	this->y = y;
}

INLINE float odVec2::operator [] (int index) const {

	return (&x)[index];
}

INLINE float &odVec2::operator [] (int index){

	return (&x)[index];
}

INLINE odVec2 &odVec2::operator = (const odVec2 &vec){

	x = vec.x;
	y = vec.y;

	return *this;
}

INLINE bool odVec2::operator == (const odVec2 &vec) const {

	if (x != vec.x || y != vec.y)
		return false;

	return true;
}

INLINE bool odVec2::operator != (const odVec2 &vec) const {

	if (x == vec.x && y == vec.y)
		return false;

	return true;
}

INLINE odVec2 odVec2::operator - () const {

	return odVec2(-x, -y);
}

INLINE odVec2 odVec2::operator + (const odVec2 &vec) const {

	return odVec2(x + vec.x, y + vec.y);
}

INLINE odVec2 odVec2::operator - (const odVec2 &vec) const {

	return odVec2(x - vec.x, y - vec.y);
}

INLINE odVec2 odVec2::operator * (const odVec2 &vec) const {

	return odVec2(x * vec.x, y * vec.y);
}

INLINE odVec2 odVec2::operator * (float scale) const {

	return odVec2(x * scale, y * scale);
}

INLINE odVec2 odVec2::operator / (const odVec2 &vec) const {

	return odVec2(x / vec.x, y / vec.y);
}

INLINE odVec2 odVec2::operator / (const float div) const {

	float	scale = 1.0f / div;

	return odVec2(x * scale, y * scale);
}

INLINE odVec2 &odVec2::operator += (const odVec2 &vec){

	x += vec.x;
	y += vec.y;

	return *this;
}

INLINE odVec2 &odVec2::operator -= (const odVec2 &vec){

	x -= vec.x;
	y -= vec.y;

	return *this;
}

INLINE odVec2 &odVec2::operator *= (const odVec2 &vec){

	x *= vec.x;
	y *= vec.y;

	return *this;
}

INLINE odVec2 &odVec2::operator *= (float scale){

	x *= scale;
	y *= scale;

	return *this;
}

INLINE odVec2 &odVec2::operator /= (const odVec2 &vec){

	x /= vec.x;
	y /= vec.y;

	return *this;
}

INLINE odVec2 &odVec2::operator /= (float div){

	float	scale = 1.0f / div;

	x *= scale;
	y *= scale;

	return *this;
}

INLINE bool odVec2::Compare (const odVec2 &vec) const {

	if (x != vec.x || y != vec.y)
		return false;

	return true;
}

INLINE bool odVec2::Compare (const odVec2 &vec, float epsilon) const {

	if (M_Fabs(x - vec.x) > epsilon)
		return false;
	if (M_Fabs(y - vec.y) > epsilon)
		return false;

	return true;
}

INLINE void odVec2::Set (float x, float y){

	this->x = x;
	this->y = y;
}

INLINE void odVec2::Clear (void){

	x = 0.0f;
	y = 0.0f;
}

INLINE bool odVec2::IsCleared (void) const {

	if (x != 0.0f || y != 0.0f)
		return false;

	return true;
}

INLINE void odVec2::Snap (void){

	x = (float)M_FtolFast(x);
	y = (float)M_FtolFast(y);
}

INLINE void odVec2::Clamp (const odVec2 &min, const odVec2 &max){

	x = (x < min.x) ? min.x : (x > max.x) ? max.x : x;
	y = (y < min.y) ? min.y : (y > max.y) ? max.y : y;
}

INLINE void odVec2::Clamp (float min, float max){

	x = (x < min) ? min : (x > max) ? max : x;
	y = (y < min) ? min : (y > max) ? max : y;
}

INLINE void odVec2::Average (const odVec2 &v1, const odVec2 &v2){

	x = (v1.x + v2.x) * 0.5f;
	y = (v1.y + v2.y) * 0.5f;
}

INLINE float odVec2::Dot (const odVec2 &vec) const {

	return x * vec.x + y * vec.y;
}

INLINE void odVec2::Lerp (const odVec2 &from, const odVec2 &to, float frac){

	if (frac <= 0.0f){
		*this = from;
		return;
	}

	if (frac >= 1.0f){
		*this = to;
		return;
	}

	x = from.x + (to.x - from.x) * frac;
	y = from.y + (to.y - from.y) * frac;
}

INLINE float odVec2::Length (void) const {

	return M_Sqrt(x*x + y*y);
}

INLINE float odVec2::LengthSqr (void) const {

	return x*x + y*y;
}

INLINE float odVec2::LengthFast (void) const {

	float	sqrLength;

	sqrLength = x*x + y*y;

	return sqrLength * M_RSqrt(sqrLength);
}

INLINE float odVec2::Normalize (void){

	float	length, invLength;

	length = M_Sqrt(x*x + y*y);

	if (length){
		invLength = 1.0f / length;

		x *= invLength;
		y *= invLength;
	}

	return length;
}

INLINE void odVec2::NormalizeFast (void){

	float	invLength;

	invLength = M_RSqrt(x*x + y*y);

	x *= invLength;
	y *= invLength;
}

INLINE const float *odVec2::ToFloatPtr (void) const {

	return &x;
}

INLINE float *odVec2::ToFloatPtr (void){

	return &x;
}

/*
 ==============================================================================

 3D VECTOR

 ==============================================================================
*/

class odVec3 {
public:
	float			x;
	float			y;
	float			z;

					odVec3 (void);
	explicit		odVec3 (float x, float y, float z);

	float			operator [] (int index) const;
	float &			operator [] (int index);

	odVec3 &		operator = (const odVec3 &vec);
	bool			operator == (const odVec3 &vec) const;
	bool			operator != (const odVec3 &vec) const;

	odVec3			operator - () const;

	odVec3			operator + (const odVec3 &vec) const;
	odVec3			operator - (const odVec3 &vec) const;
	odVec3			operator * (const odVec3 &vec) const;
	odVec3			operator * (float scale) const;
	odVec3			operator / (const odVec3 &vec) const;
	odVec3			operator / (float div) const;
	odVec3 &		operator += (const odVec3 &vec);
	odVec3 &		operator -= (const odVec3 &vec);
	odVec3 &		operator *= (const odVec3 &vec);
	odVec3 &		operator *= (float scale);
	odVec3 &		operator /= (const odVec3 &vec);
	odVec3 &		operator /= (float div);

	bool			Compare (const odVec3 &vec) const;
	bool			Compare (const odVec3 &vec, float epsilon = 0.0f) const;
	void			Set (float x, float y, float z);
	void			Clear (void);
	bool			IsCleared (void) const;
	void			Snap (void);
	void			Clamp (const odVec3 &min, const odVec3 &max);
	void			Clamp (float min, float max);
	void			Average (const odVec3 &v1, const odVec3 &v2);
	float			Dot (const odVec3 &vec) const;
	void			Cross (const odVec3 &v1, const odVec3 &v2);
	void			Lerp (const odVec3 &from, const odVec3 &to, float frac);
	void			SLerp (const odVec3 &from, const odVec3 &to, float frac);
	void			Reflect (const odVec3 &vec, const odVec3 &normal);
	float			Distance (const odVec3 &vec) const;
	float			DistanceSqr (const odVec3 &vec) const;
	float			DistanceFast (const odVec3 &vec) const;
	float			Length (void) const;
	float			LengthSqr (void) const;
	float			LengthFast (void) const;
	float			Normalize (void);
	void			NormalizeFast (void);
	void			NormalVectors (odVec3 &right, odVec3 &up) const;

	const float *	ToFloatPtr (void) const;
	float *			ToFloatPtr (void);
	const odVec2 &	ToVec2 (void) const;
	odVec2 &		ToVec2 (void);

	float			ToPitch (void) const;
	float			ToYaw (void) const;
	odAngles		ToAngles (void) const;
	odMat3			ToMat3 (void) const;
	const char *	ToString (int precision = 2) const;
};

INLINE odVec3::odVec3 (void){

}

INLINE odVec3::odVec3 (float x, float y, float z){

	this->x = x;
	this->y = y;
	this->z = z;
}

INLINE float odVec3::operator [] (int index) const {

	return (&x)[index];
}

INLINE float &odVec3::operator [] (int index){

	return (&x)[index];
}

INLINE odVec3 &odVec3::operator = (const odVec3 &vec){

	x = vec.x;
	y = vec.y;
	z = vec.z;

	return *this;
}

INLINE bool odVec3::operator == (const odVec3 &vec) const {

	if (x != vec.x || y != vec.y || z != vec.z)
		return false;

	return true;
}

INLINE bool odVec3::operator != (const odVec3 &vec) const {

	if (x == vec.x && y == vec.y && z == vec.z)
		return false;

	return true;
}

INLINE odVec3 odVec3::operator - () const {

	return odVec3(-x, -y, -z);
}

INLINE odVec3 odVec3::operator + (const odVec3 &vec) const {

	return odVec3(x + vec.x, y + vec.y, z + vec.z);
}

INLINE odVec3 odVec3::operator - (const odVec3 &vec) const {

	return odVec3(x - vec.x, y - vec.y, z - vec.z);
}

INLINE odVec3 odVec3::operator * (const odVec3 &vec) const {

	return odVec3(x * vec.x, y * vec.y, z * vec.z);
}

INLINE odVec3 odVec3::operator * (float scale) const {

	return odVec3(x * scale, y * scale, z * scale);
}

INLINE odVec3 odVec3::operator / (const odVec3 &vec) const {

	return odVec3(x / vec.x, y / vec.y, z / vec.z);
}

INLINE odVec3 odVec3::operator / (const float div) const {

	float	scale = 1.0f / div;

	return odVec3(x * scale, y * scale, z * scale);
}

INLINE odVec3 &odVec3::operator += (const odVec3 &vec){

	x += vec.x;
	y += vec.y;
	z += vec.z;

	return *this;
}

INLINE odVec3 &odVec3::operator -= (const odVec3 &vec){

	x -= vec.x;
	y -= vec.y;
	z -= vec.z;

	return *this;
}

INLINE odVec3 &odVec3::operator *= (const odVec3 &vec){

	x *= vec.x;
	y *= vec.y;
	z *= vec.z;

	return *this;
}

INLINE odVec3 &odVec3::operator *= (float scale){

	x *= scale;
	y *= scale;
	z *= scale;

	return *this;
}

INLINE odVec3 &odVec3::operator /= (const odVec3 &vec){

	x /= vec.x;
	y /= vec.y;
	z /= vec.z;

	return *this;
}

INLINE odVec3 &odVec3::operator /= (float div){

	float	scale = 1.0f / div;

	x *= scale;
	y *= scale;
	z *= scale;

	return *this;
}

INLINE bool odVec3::Compare (const odVec3 &vec) const {

	if (x != vec.x || y != vec.y || z != vec.z)
		return false;

	return true;
}

INLINE bool odVec3::Compare (const odVec3 &vec, float epsilon) const {

	if (M_Fabs(x - vec.x) > epsilon)
		return false;
	if (M_Fabs(y - vec.y) > epsilon)
		return false;
	if (M_Fabs(z - vec.z) > epsilon)
		return false;

	return true;
}

INLINE void odVec3::Set (float x, float y, float z){

	this->x = x;
	this->y = y;
	this->z = z;
}

INLINE void odVec3::Clear (void){

	x = 0.0f;
	y = 0.0f;
	z = 0.0f;
}

INLINE bool odVec3::IsCleared (void) const {

	if (x != 0.0f || y != 0.0f || z != 0.0f)
		return false;

	return true;
}

INLINE void odVec3::Snap (void){

	x = (float)M_FtolFast(x);
	y = (float)M_FtolFast(y);
	z = (float)M_FtolFast(z);
}

INLINE void odVec3::Clamp (const odVec3 &min, const odVec3 &max){

	x = (x < min.x) ? min.x : (x > max.x) ? max.x : x;
	y = (y < min.y) ? min.y : (y > max.y) ? max.y : y;
	z = (z < min.z) ? min.z : (z > max.z) ? max.z : z;
}

INLINE void odVec3::Clamp (float min, float max){

	x = (x < min) ? min : (x > max) ? max : x;
	y = (y < min) ? min : (y > max) ? max : y;
	z = (z < min) ? min : (z > max) ? max : z;
}

INLINE void odVec3::Average (const odVec3 &v1, const odVec3 &v2){

	x = (v1.x + v2.x) * 0.5f;
	y = (v1.y + v2.y) * 0.5f;
	z = (v1.z + v2.z) * 0.5f;
}

INLINE float odVec3::Dot (const odVec3 &vec) const {

	return x * vec.x + y * vec.y + z * vec.z;
}

INLINE void odVec3::Cross (const odVec3 &v1, const odVec3 &v2){

	x = v1.y * v2.z - v1.z * v2.y;
	y = v1.z * v2.x - v1.x * v2.z;
	z = v1.x * v2.y - v1.y * v2.x;
}

INLINE void odVec3::Lerp (const odVec3 &from, const odVec3 &to, float frac){

	if (frac <= 0.0f){
		*this = from;
		return;
	}

	if (frac >= 1.0f){
		*this = to;
		return;
	}

	x = from.x + (to.x - from.x) * frac;
	y = from.y + (to.y - from.y) * frac;
	z = from.z + (to.z - from.z) * frac;
}

INLINE void odVec3::SLerp (const odVec3 &from, const odVec3 &to, float frac){

	float	omega, sinom, cosom;
	float	fScale, tScale;

	if (frac <= 0.0f){
		*this = from;
		return;
	}

	if (frac >= 1.0f){
		*this = to;
		return;
	}

	cosom = from.x * to.x + from.y * to.y + from.z * to.z;

	if ((1.0f - cosom) > 0.0f){
		omega = M_ACos(cosom);
		sinom = 1.0f / M_Sin(omega);

		fScale = M_Sin((1.0f - frac) * omega) * sinom;
		tScale = M_Sin(frac * omega) * sinom;
	}
	else {
		fScale = 1.0f - frac;
		tScale = frac;
	}

	x = from.x * fScale + to.x * tScale;
	y = from.y * fScale + to.y * tScale;
	z = from.z * fScale + to.z * tScale;
}

INLINE void odVec3::Reflect (const odVec3 &vec, const odVec3 &normal){

	float	d;

	d = 2.0f * (vec.x * normal.x + vec.y * normal.y + vec.z * normal.z);

	x = vec.x - normal.x * d;
	y = vec.y - normal.y * d;
	z = vec.z - normal.z * d;
}

INLINE float odVec3::Distance (const odVec3 &vec) const {

	float	xd, yd, zd;

	xd = vec.x - x;
	yd = vec.y - y;
	zd = vec.z - z;

	return M_Sqrt(xd*xd + yd*yd + zd*zd);
}

INLINE float odVec3::DistanceSqr (const odVec3 &vec) const {

	float	xd, yd, zd;

	xd = vec.x - x;
	yd = vec.y - y;
	zd = vec.z - z;

	return xd*xd + yd*yd + zd*zd;
}

INLINE float odVec3::DistanceFast (const odVec3 &vec) const {

	float	xd, yd, zd;
	float	sqrLength;

	xd = vec.x - x;
	yd = vec.y - y;
	zd = vec.z - z;

	sqrLength = xd*xd + yd*yd + zd*zd;

	return sqrLength * M_RSqrt(sqrLength);
}

INLINE float odVec3::Length (void) const {

	return M_Sqrt(x*x + y*y + z*z);
}

INLINE float odVec3::LengthSqr (void) const {

	return x*x + y*y + z*z;
}

INLINE float odVec3::LengthFast (void) const {

	float	sqrLength;

	sqrLength = x*x + y*y + z*z;

	return sqrLength * M_RSqrt(sqrLength);
}

INLINE float odVec3::Normalize (void){

	float	length, invLength;

	length = M_Sqrt(x*x + y*y + z*z);

	if (length){
		invLength = 1.0f / length;

		x *= invLength;
		y *= invLength;
		z *= invLength;
	}

	return length;
}

INLINE void odVec3::NormalizeFast (void){

	float	invLength;

	invLength = M_RSqrt(x*x + y*y + z*z);

	x *= invLength;
	y *= invLength;
	z *= invLength;
}

INLINE const float *odVec3::ToFloatPtr (void) const {

	return &x;
}

INLINE float *odVec3::ToFloatPtr (void){

	return &x;
}

INLINE const odVec2 &odVec3::ToVec2 (void) const {

	return *reinterpret_cast <const odVec2 *> (this);
}

INLINE odVec2 &odVec3::ToVec2 (void){

	return *reinterpret_cast <odVec2 *> (this);
}

/*
 ==============================================================================

 4D VECTOR

 ==============================================================================
*/

class odVec4 {
public:
	float			x;
	float			y;
	float			z;
	float			w;

					odVec4 (void);
	explicit		odVec4 (float x, float y, float z, float w);

	float			operator [] (int index) const;
	float &			operator [] (int index);

	odVec4 &		operator = (const odVec4 &vec);
	bool			operator == (const odVec4 &vec) const;
	bool			operator != (const odVec4 &vec) const;

	odVec4			operator - () const;

	odVec4			operator + (const odVec4 &vec) const;
	odVec4			operator - (const odVec4 &vec) const;
	odVec4			operator * (const odVec4 &vec) const;
	odVec4			operator * (float scale) const;
	odVec4			operator / (const odVec4 &vec) const;
	odVec4			operator / (float div) const;
	odVec4 &		operator += (const odVec4 &vec);
	odVec4 &		operator -= (const odVec4 &vec);
	odVec4 &		operator *= (const odVec4 &vec);
	odVec4 &		operator *= (float scale);
	odVec4 &		operator /= (const odVec4 &vec);
	odVec4 &		operator /= (float div);

	bool			Compare (const odVec4 &vec) const;
	bool			Compare (const odVec4 &vec, float epsilon = 0.0f) const;
	void			Set (float x, float y, float z, float w);
	void			Clear (void);
	bool			IsCleared (void) const;
	void			Snap (void);
	void			Clamp (const odVec4 &min, const odVec4 &max);
	void			Clamp (float min, float max);
	void			Average (const odVec4 &v1, const odVec4 &v2);
	float			Dot (const odVec4 &vec) const;
	void			Lerp (const odVec4 &from, const odVec4 &to, float frac);
	float			Length (void) const;
	float			LengthSqr (void) const;
	float			LengthFast (void) const;
	float			Normalize (void);
	void			NormalizeFast (void);

	const float *	ToFloatPtr (void) const;
	float *			ToFloatPtr (void);
	const odVec2 &	ToVec2 (void) const;
	odVec2 &		ToVec2 (void);
	const odVec3 &	ToVec3 (void) const;
	odVec3 &		ToVec3 (void);

	const char *	ToString (int precision = 2) const;
};

INLINE odVec4::odVec4 (void){

}

INLINE odVec4::odVec4 (float x, float y, float z, float w){

	this->x = x;
	this->y = y;
	this->z = z;
	this->w = w;
}

INLINE float odVec4::operator [] (int index) const {

	return (&x)[index];
}

INLINE float &odVec4::operator [] (int index){

	return (&x)[index];
}

INLINE odVec4 &odVec4::operator = (const odVec4 &vec){

	x = vec.x;
	y = vec.y;
	z = vec.z;
	w = vec.w;

	return *this;
}

INLINE bool odVec4::operator == (const odVec4 &vec) const {

	if (x != vec.x || y != vec.y || z != vec.z || w != vec.w)
		return false;

	return true;
}

INLINE bool odVec4::operator != (const odVec4 &vec) const {

	if (x == vec.x && y == vec.y && z == vec.z && w == vec.w)
		return false;

	return true;
}

INLINE odVec4 odVec4::operator - () const {

	return odVec4(-x, -y, -z, -w);
}

INLINE odVec4 odVec4::operator + (const odVec4 &vec) const {

	return odVec4(x + vec.x, y + vec.y, z + vec.z, w + vec.w);
}

INLINE odVec4 odVec4::operator - (const odVec4 &vec) const {

	return odVec4(x - vec.x, y - vec.y, z - vec.z, w - vec.w);
}

INLINE odVec4 odVec4::operator * (const odVec4 &vec) const {

	return odVec4(x * vec.x, y * vec.y, z * vec.z, w * vec.w);
}

INLINE odVec4 odVec4::operator * (float scale) const {

	return odVec4(x * scale, y * scale, z * scale, w * scale);
}

INLINE odVec4 odVec4::operator / (const odVec4 &vec) const {

	return odVec4(x / vec.x, y / vec.y, z / vec.z, w / vec.w);
}

INLINE odVec4 odVec4::operator / (const float div) const {

	float	scale = 1.0f / div;

	return odVec4(x * scale, y * scale, z * scale, w * scale);
}

INLINE odVec4 &odVec4::operator += (const odVec4 &vec){

	x += vec.x;
	y += vec.y;
	z += vec.z;
	w += vec.w;

	return *this;
}

INLINE odVec4 &odVec4::operator -= (const odVec4 &vec){

	x -= vec.x;
	y -= vec.y;
	z -= vec.z;
	w -= vec.w;

	return *this;
}

INLINE odVec4 &odVec4::operator *= (const odVec4 &vec){

	x *= vec.x;
	y *= vec.y;
	z *= vec.z;
	w *= vec.w;

	return *this;
}

INLINE odVec4 &odVec4::operator *= (float scale){

	x *= scale;
	y *= scale;
	z *= scale;
	w *= scale;

	return *this;
}

INLINE odVec4 &odVec4::operator /= (const odVec4 &vec){

	x /= vec.x;
	y /= vec.y;
	z /= vec.z;
	w /= vec.w;

	return *this;
}

INLINE odVec4 &odVec4::operator /= (float div){

	float	scale = 1.0f / div;

	x *= scale;
	y *= scale;
	z *= scale;
	w *= scale;

	return *this;
}

INLINE bool odVec4::Compare (const odVec4 &vec) const {

	if (x != vec.x || y != vec.y || z != vec.z || w != vec.w)
		return false;

	return true;
}

INLINE bool odVec4::Compare (const odVec4 &vec, float epsilon) const {

	if (M_Fabs(x - vec.x) > epsilon)
		return false;
	if (M_Fabs(y - vec.y) > epsilon)
		return false;
	if (M_Fabs(z - vec.z) > epsilon)
		return false;
	if (M_Fabs(w - vec.w) > epsilon)
		return false;

	return true;
}

INLINE void odVec4::Set (float x, float y, float z, float w){

	this->x = x;
	this->y = y;
	this->z = z;
	this->w = w;
}

INLINE void odVec4::Clear (void){

	x = 0.0f;
	y = 0.0f;
	z = 0.0f;
	w = 0.0f;
}

INLINE bool odVec4::IsCleared (void) const {

	if (x != 0.0f || y != 0.0f || z != 0.0f || w != 0.0f)
		return false;

	return true;
}

INLINE void odVec4::Snap (void){

	x = (float)M_FtolFast(x);
	y = (float)M_FtolFast(y);
	z = (float)M_FtolFast(z);
	w = (float)M_FtolFast(w);
}

INLINE void odVec4::Clamp (const odVec4 &min, const odVec4 &max){

	x = (x < min.x) ? min.x : (x > max.x) ? max.x : x;
	y = (y < min.y) ? min.y : (y > max.y) ? max.y : y;
	z = (z < min.z) ? min.z : (z > max.z) ? max.z : z;
	w = (w < min.w) ? min.w : (w > max.w) ? max.w : w;
}

INLINE void odVec4::Clamp (float min, float max){

	x = (x < min) ? min : (x > max) ? max : x;
	y = (y < min) ? min : (y > max) ? max : y;
	z = (z < min) ? min : (z > max) ? max : z;
	w = (w < min) ? min : (w > max) ? max : w;
}

INLINE void odVec4::Average (const odVec4 &v1, const odVec4 &v2){

	x = (v1.x + v2.x) * 0.5f;
	y = (v1.y + v2.y) * 0.5f;
	z = (v1.z + v2.z) * 0.5f;
	w = (v1.w + v2.w) * 0.5f;
}

INLINE float odVec4::Dot (const odVec4 &vec) const {

	return x * vec.x + y * vec.y + z * vec.z + w * vec.w;
}

INLINE void odVec4::Lerp (const odVec4 &from, const odVec4 &to, float frac){

	if (frac <= 0.0f){
		*this = from;
		return;
	}

	if (frac >= 1.0f){
		*this = to;
		return;
	}

	x = from.x + (to.x - from.x) * frac;
	y = from.y + (to.y - from.y) * frac;
	z = from.z + (to.z - from.z) * frac;
	w = from.w + (to.w - from.w) * frac;
}

INLINE float odVec4::Length (void) const {

	return M_Sqrt(x*x + y*y + z*z + w*w);
}

INLINE float odVec4::LengthSqr (void) const {

	return x*x + y*y + z*z + w*w;
}

INLINE float odVec4::LengthFast (void) const {

	float	sqrLength;

	sqrLength = x*x + y*y + z*z + w*w;

	return sqrLength * M_RSqrt(sqrLength);
}

INLINE float odVec4::Normalize (void){

	float	length, invLength;

	length = M_Sqrt(x*x + y*y + z*z + w*w);

	if (length){
		invLength = 1.0f / length;

		x *= invLength;
		y *= invLength;
		z *= invLength;
		w *= invLength;
	}

	return length;
}

INLINE void odVec4::NormalizeFast (void){

	float	invLength;

	invLength = M_RSqrt(x*x + y*y + z*z + w*w);

	x *= invLength;
	y *= invLength;
	z *= invLength;
	w *= invLength;
}

INLINE const float *odVec4::ToFloatPtr (void) const {

	return &x;
}

INLINE float *odVec4::ToFloatPtr (void){

	return &x;
}

INLINE const odVec2 &odVec4::ToVec2 (void) const {

	return *reinterpret_cast <const odVec2 *> (this);
}

INLINE odVec2 &odVec4::ToVec2 (void){

	return *reinterpret_cast <odVec2 *> (this);
}

INLINE const odVec3 &odVec4::ToVec3 (void) const {

	return *reinterpret_cast <const odVec3 *> (this);
}

INLINE odVec3 &odVec4::ToVec3 (void){

	return *reinterpret_cast <odVec3 *> (this);
}

/*
 ==============================================================================

 5D VECTOR

 ==============================================================================
*/

class odVec5 {
public:
	float			x;
	float			y;
	float			z;
	float			s;
	float			t;

					odVec5 (void);
	explicit		odVec5 (float x, float y, float z, float s, float t);

	float			operator [] (int index) const;
	float &			operator [] (int index);

	odVec5 &		operator = (const odVec5 &vec);
	bool			operator == (const odVec5 &vec) const;
	bool			operator != (const odVec5 &vec) const;

	odVec5			operator - () const;

	odVec5			operator + (const odVec5 &vec) const;
	odVec5			operator - (const odVec5 &vec) const;
	odVec5			operator * (const odVec5 &vec) const;
	odVec5			operator * (float scale) const;
	odVec5			operator / (const odVec5 &vec) const;
	odVec5			operator / (float div) const;
	odVec5 &		operator += (const odVec5 &vec);
	odVec5 &		operator -= (const odVec5 &vec);
	odVec5 &		operator *= (const odVec5 &vec);
	odVec5 &		operator *= (float scale);
	odVec5 &		operator /= (const odVec5 &vec);
	odVec5 &		operator /= (float div);

	bool			Compare (const odVec5 &vec) const;
	bool			Compare (const odVec5 &vec, float epsilon = 0.0f) const;
	void			Set (float x, float y, float z, float s, float t);
	void			Clear (void);
	bool			IsCleared (void) const;
	void			Snap (void);
	void			Clamp (const odVec5 &min, const odVec5 &max);
	void			Clamp (float min, float max);
	void			Average (const odVec5 &v1, const odVec5 &v2);

	const float *	ToFloatPtr (void) const;
	float *			ToFloatPtr (void);
	const odVec2 &	ToVec2 (void) const;
	odVec2 &		ToVec2 (void);
	const odVec3 &	ToVec3 (void) const;
	odVec3 &		ToVec3 (void);
	const odVec4 &	ToVec4 (void) const;
	odVec4 &		ToVec4 (void);

	const char *	ToString (int precision = 2) const;
};

INLINE odVec5::odVec5 (void){

}

INLINE odVec5::odVec5 (float x, float y, float z, float s, float t){

	this->x = x;
	this->y = y;
	this->z = z;
	this->s = s;
	this->t = t;
}

INLINE float odVec5::operator [] (int index) const {

	return (&x)[index];
}

INLINE float &odVec5::operator [] (int index){

	return (&x)[index];
}

INLINE odVec5 &odVec5::operator = (const odVec5 &vec){

	x = vec.x;
	y = vec.y;
	z = vec.z;
	s = vec.s;
	t = vec.t;

	return *this;
}

INLINE bool odVec5::operator == (const odVec5 &vec) const {

	if (x != vec.x || y != vec.y || z != vec.z || s != vec.s || t != vec.t)
		return false;

	return true;
}

INLINE bool odVec5::operator != (const odVec5 &vec) const {

	if (x == vec.x && y == vec.y && z == vec.z && s == vec.s && t == vec.t)
		return false;

	return true;
}

INLINE odVec5 odVec5::operator - () const {

	return odVec5(-x, -y, -z, -s, -t);
}

INLINE odVec5 odVec5::operator + (const odVec5 &vec) const {

	return odVec5(x + vec.x, y + vec.y, z + vec.z, s + vec.s, t + vec.t);
}

INLINE odVec5 odVec5::operator - (const odVec5 &vec) const {

	return odVec5(x - vec.x, y - vec.y, z - vec.z, s - vec.s, t - vec.t);
}

INLINE odVec5 odVec5::operator * (const odVec5 &vec) const {

	return odVec5(x * vec.x, y * vec.y, z * vec.z, s * vec.s, t * vec.t);
}

INLINE odVec5 odVec5::operator * (float scale) const {

	return odVec5(x * scale, y * scale, z * scale, s * scale, t * scale);
}

INLINE odVec5 odVec5::operator / (const odVec5 &vec) const {

	return odVec5(x / vec.x, y / vec.y, z / vec.z, s / vec.s, t / vec.t);
}

INLINE odVec5 odVec5::operator / (const float div) const {

	float	scale = 1.0f / div;

	return odVec5(x * scale, y * scale, z * scale, s * scale, t * scale);
}

INLINE odVec5 &odVec5::operator += (const odVec5 &vec){

	x += vec.x;
	y += vec.y;
	z += vec.z;
	s += vec.s;
	t += vec.t;

	return *this;
}

INLINE odVec5 &odVec5::operator -= (const odVec5 &vec){

	x -= vec.x;
	y -= vec.y;
	z -= vec.z;
	s -= vec.s;
	t -= vec.t;

	return *this;
}

INLINE odVec5 &odVec5::operator *= (const odVec5 &vec){

	x *= vec.x;
	y *= vec.y;
	z *= vec.z;
	s *= vec.s;
	t *= vec.t;

	return *this;
}

INLINE odVec5 &odVec5::operator *= (float scale){

	x *= scale;
	y *= scale;
	z *= scale;
	s *= scale;
	t *= scale;

	return *this;
}

INLINE odVec5 &odVec5::operator /= (const odVec5 &vec){

	x /= vec.x;
	y /= vec.y;
	z /= vec.z;
	s /= vec.s;
	t /= vec.t;

	return *this;
}

INLINE odVec5 &odVec5::operator /= (float div){

	float	scale = 1.0f / div;

	x *= scale;
	y *= scale;
	z *= scale;
	s *= scale;
	t *= scale;

	return *this;
}

INLINE bool odVec5::Compare (const odVec5 &vec) const {

	if (x != vec.x || y != vec.y || z != vec.z || s != vec.s || t != vec.t)
		return false;

	return true;
}

INLINE bool odVec5::Compare (const odVec5 &vec, float epsilon) const {

	if (M_Fabs(x - vec.x) > epsilon)
		return false;
	if (M_Fabs(y - vec.y) > epsilon)
		return false;
	if (M_Fabs(z - vec.z) > epsilon)
		return false;
	if (M_Fabs(s - vec.s) > epsilon)
		return false;
	if (M_Fabs(t - vec.t) > epsilon)
		return false;

	return true;
}

INLINE void odVec5::Set (float x, float y, float z, float s, float t){

	this->x = x;
	this->y = y;
	this->z = z;
	this->s = s;
	this->t = t;
}

INLINE void odVec5::Clear (void){

	x = 0.0f;
	y = 0.0f;
	z = 0.0f;
	s = 0.0f;
	t = 0.0f;
}

INLINE bool odVec5::IsCleared (void) const {

	if (x != 0.0f || y != 0.0f || z != 0.0f || s != 0.0f || t != 0.0f)
		return false;

	return true;
}

INLINE void odVec5::Snap (void){

	x = (float)M_FtolFast(x);
	y = (float)M_FtolFast(y);
	z = (float)M_FtolFast(z);
	s = (float)M_FtolFast(s);
	t = (float)M_FtolFast(t);
}

INLINE void odVec5::Clamp (const odVec5 &min, const odVec5 &max){

	x = (x < min.x) ? min.x : (x > max.x) ? max.x : x;
	y = (y < min.y) ? min.y : (y > max.y) ? max.y : y;
	z = (z < min.z) ? min.z : (z > max.z) ? max.z : z;
	s = (s < min.s) ? min.s : (s > max.s) ? max.s : s;
	t = (t < min.t) ? min.t : (t > max.t) ? max.t : t;
}

INLINE void odVec5::Clamp (float min, float max){

	x = (x < min) ? min : (x > max) ? max : x;
	y = (y < min) ? min : (y > max) ? max : y;
	z = (z < min) ? min : (z > max) ? max : z;
	s = (s < min) ? min : (s > max) ? max : s;
	t = (t < min) ? min : (t > max) ? max : t;
}

INLINE void odVec5::Average (const odVec5 &v1, const odVec5 &v2){

	x = (v1.x + v2.x) * 0.5f;
	y = (v1.y + v2.y) * 0.5f;
	z = (v1.z + v2.z) * 0.5f;
	s = (v1.s + v2.s) * 0.5f;
	t = (v1.t + v2.t) * 0.5f;
}

INLINE const float *odVec5::ToFloatPtr (void) const {

	return &x;
}

INLINE float *odVec5::ToFloatPtr (void){

	return &x;
}

INLINE const odVec2 &odVec5::ToVec2 (void) const {

	return *reinterpret_cast <const odVec2 *> (this);
}

INLINE odVec2 &odVec5::ToVec2 (void){

	return *reinterpret_cast <odVec2 *> (this);
}

INLINE const odVec3 &odVec5::ToVec3 (void) const {

	return *reinterpret_cast <const odVec3 *> (this);
}

INLINE odVec3 &odVec5::ToVec3 (void){

	return *reinterpret_cast <odVec3 *> (this);
}

INLINE const odVec4 &odVec5::ToVec4 (void) const {

	return *reinterpret_cast <const odVec4 *> (this);
}

INLINE odVec4 &odVec5::ToVec4 (void){

	return *reinterpret_cast <odVec4 *> (this);
}


#endif	// __MATH_VECTOR_H__
